package ge.telasi.tasks.ejb;

import ge.telasi.tasks.controller.AnalyzeController;
import ge.telasi.tasks.controller.AppConfigController;
import ge.telasi.tasks.controller.BinaryDataController;
import ge.telasi.tasks.controller.NotificationManager;
import ge.telasi.tasks.controller.StructureController;
import ge.telasi.tasks.controller.TaskController;
import ge.telasi.tasks.controller.UserController;
import ge.telasi.tasks.model.AppConfig;
import ge.telasi.tasks.model.TaskAttachment;
import ge.telasi.tasks.model.FlowPermission;
import ge.telasi.tasks.model.Group;
import ge.telasi.tasks.model.Structure;
import ge.telasi.tasks.model.Task;
import ge.telasi.tasks.model.TaskList;
import ge.telasi.tasks.model.TaskReceiver;
import ge.telasi.tasks.model.TaskRelation;
import ge.telasi.tasks.model.User;
import ge.telasi.tasks.model.copy.BinaryDataCopy;
import ge.telasi.tasks.search.Condition;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;

/**
 * @author dimitri
 */
@Stateless
public class TaskFacadeBean implements TaskFacadeRemote {
    private static final long serialVersionUID = -7005149234252614658L;

    @PersistenceUnit(name = "tasks_pu")
    private EntityManagerFactory emf;

    EntityManager getEm() {
        return emf.createEntityManager();
    }

    User authorize(EntityManager em, Map credentials) {
        String username = (String) credentials.get("username");
        String password = (String) credentials.get("password");
        return new UserController().authorize(em, username, password);
    }

    // <editor-fold defaultstate="collapsed" desc="Structure">

    public List<Structure> getRootStructures() {
        EntityManager em = getEm();
        List<Structure> structs = new StructureController().getRootStructures(em);
        for (Structure str : structs) {
            em.refresh(str);
            exposeStructure(str);
        }
        return structs;
    }
    
    private void exposeStructure(Structure structure) {
        for(Structure str : structure.getChildren()) {
            exposeStructure(str);
        }
    }

    public Structure createStructure(Map credentials, Structure structure) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new StructureController().createStructure(em, user, structure);
    }

    public Structure updateStructure(Map credentials, Structure structure) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new StructureController().updateStructure(em, user, structure);
    }

    public void deleteStructure(Map credentials, Structure structure) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        new StructureController().deleteStructure(em, user, structure);
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="App Configuration">

    public List<AppConfig> getAppConfigs(Map credentials) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new AppConfigController().getAppConfigs(em, user);
    }

    public AppConfig updateAppConfig(Map credentials, AppConfig config) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new AppConfigController().updateAppConfig(em, user, config);
    }



    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="User">

    public User authorize(String username, String password) {
        return new UserController().authorize(getEm(), username, password);
    }

    public User register(User user, String password) {
        EntityManager em = getEm();
        User newUser = new UserController().register(em, user, password);
        new NotificationManager().notifyNewUserRegistration(em, newUser);
        return newUser;
    }

    public List<User> getAllUsers(Map credentials) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new UserController().getAllUsers(em, user);
    }

    public List<User> getAllActiveUsers(Map credentials) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new UserController().getAllActiveUsers(em, user);
    }
    
    public User updateUserbyAdmin(Map credentials, User user) {
        EntityManager em = getEm();
        User admin = authorize(em, credentials);
        return new UserController().updateUserByAdmin(em, admin, user);
    }

    public User changePassword(Map credentials, String newPassword) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new UserController().changePassword(em, user, newPassword);
    }

    public List<Group> getAllGroups(Map credentials) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new UserController().getAllGroups(em, user);
    }

    public Group createGroup(Map credentials, Group group) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new UserController().createGroup(em, user, group);
    }

    public Group updateGroup(Map credentials, Group group) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new UserController().updateGroup(em, user, group);
    }

    public boolean deleteGroup(Map credentials, Group group) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new UserController().deleteGroup(em, user, group);
    }

    public List<User> getGroupUsers(Map credentials, Group group) {
        EntityManager em = getEm();
        List<User> users = new UserController().getGroupUsers(em, group);
        users.size();
        return users;
    }

    public List<Group> getUserGroups(Map credentials, User user) {
        EntityManager em = getEm();
        List<Group> groups = new UserController().getUserGroups(em, user);
        groups.size();
        return groups;
    }

    public void addUsersToGroup(Map credentials, Group group, List<User> users) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        new UserController().addUsersToGroup(em, user, group, users);
    }

    public void removeUsersFromGroup(Map credentials, Group group, List<User> users) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        new UserController().removeUsersFromGroup(em, user, group, users);
    }

    public User getUserWithRelations(Map credentials, User user) {
        EntityManager em = getEm();
        authorize(em, credentials);
        user = new UserController().find(em, user.getUsername());
        user.getAssistants().size();
        user.getBosses().size();
        return user;
    }

    public User addUserRelation(Map credentials, User root, List<User> users, boolean assistant) {
        EntityManager em = getEm();
        User admin = authorize(em, credentials);
        root = new UserController().addRelation(em, admin, root, users, assistant);
        root.getAssistants().size();
        root.getBosses().size();
        return root;
    }

    public User removeUserRelation(Map credentials, User root, List<User> users, boolean assistant) {
        EntityManager em = getEm();
        User admin = authorize(em, credentials);
        root = new UserController().removeRelation(em, admin, root, users, assistant);
        root.getAssistants().size();
        root.getBosses().size();
        return root;
    }

    public void changePasswordAdmin(Map credentials, User user, String password) {
        EntityManager em = getEm();
        User admin = authorize(em, credentials);
        new UserController().changePasswordAdmin(em, admin, user, password);
    }

    public long uploadUserImage(Map credentials, byte[] data) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new UserController().uploadUserImage(em, user, data);
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Task">

    public List<FlowPermission> getFlowPermissions(Map credentials, int taskType) {
        EntityManager em = getEm();
        return new TaskController().getFlowPermissions(em, taskType);
    }

    public FlowPermission createFlowPermission(Map credentials, FlowPermission permission) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new TaskController().createPermission(em, user, permission);
    }

    public void deleteFlowPermission(Map credentials, FlowPermission permission) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        new TaskController().deletePermission(em, user, permission);
    }

    public void deleteFlowPermissions(Map credentials, List<FlowPermission> permissions) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        new TaskController().deletePermissions(em, user, permissions);
    }
    
    public Integer[] getAllowedTaskStatuses(Map credentials, Task task) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new TaskController().getAllowedStatuses(em, task, user);
    }

    public Task createTask(Map credentials, Task task, User forUser, boolean draft) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        TaskController controller = new TaskController();
        return controller.createTask(em, user, task, forUser, draft);
    }

    public TaskList findTasks(Map credentials, int page, int perPage, List<Condition> conditions) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new TaskController().findTasks(em, user, page, perPage, conditions);
    }

    public Task getTask(Map credentials, Task task) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        TaskController tc = new TaskController();
        task = tc.findTask(em, task.getId());
        tc.markAsRead(em, task.getId(), user.getId());
        exposeTask(task);
        return task;
    }

    public Task changeReceivers(Map credentials, Task task, List<TaskReceiver> receivers, boolean copy) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new TaskController().changeReceivers(em, user, task, receivers, copy);
    }

    public Task changeTaskSubject(Map credentials, Task task, String newSubject) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new TaskController().changeSubject(em, user, task, newSubject);
    }

    public Task changeTaskPriority(Map credentials, Task task, Calendar dueDate, int priority) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new TaskController().changePriority(em, user, task, dueDate, priority);
    }

    public Task changeTaskStatus(Map credentials, Task task, String comment, int newStatus) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new TaskController().changeStatus(em, user, task, comment, newStatus);
    }

    public TaskAttachment uploadAttachment(Map credentials, Task task, TaskAttachment data, byte[] content) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        TaskAttachment newData = new TaskController().uploadAttachment(em, user, task, data, content);
        em.flush();
        BinaryDataCopy copier = new BinaryDataCopy();
        return copier.createClone(newData);
    }

    public byte[] downloadAttachment(Map credentials, Task task, TaskAttachment data) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new TaskController().downloadAttachment(em, user, task, data);
    }

    public void removeAttachment(Map credentials, List<TaskAttachment> attachments) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        new TaskController().removeAttachments(em, user, attachments);
    }

    public void deleteTask(Map credentials, Task task) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        new TaskController().deleteTask(em, user, task);
    }

    public Task addTaskParentRelation(Map credentials, Task task, List<TaskRelation> relations) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        task = new TaskController().addParentRelation(em, user, task, relations);
        exposeTask(task);
        return task;
    }

    public Task removeTaskParentRelation(Map credentials, Task task, List<TaskRelation> relations) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        task = new TaskController().removeParentRelation(em, user, task, relations);
        exposeTask(task);
        return task;
    }

    private void exposeTask(Task task) {
        task.getBodies().size();
        task.getReceivers().size();
        task.getAttachments().size();
        task.getParents().size();
        task.getChildren().size();
    }

    public byte[] getTaskReport(Map credentials, Task task) {
        EntityManager em = getEm();
        return new TaskController().getTaskReport(em, task.getId());
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Binary Data">

    public byte[] download(Map credentials, long binaryId) {
        EntityManager em = getEm();
        return new BinaryDataController().getData(em, binaryId);
    }

    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Analyze">

    public List getTaskCompetedReportData(Map credentials, Calendar c1, Calendar c2) {
        EntityManager em = getEm();
        User user = authorize(em, credentials);
        return new AnalyzeController().getTasksCompletedReport(em, user, c1, c2);
    }

    // </editor-fold>

}
